﻿using client.messengers.clients;
using client.messengers.register;
using common.libs;
using common.server;
using common.socks5;
using System;

namespace client.service.socks5
{
    public class Socks5ClientHandler : ISocks5ClientHandler
    {
        private readonly Socks5MessengerSender socks5MessengerSender;
        private readonly RegisterStateInfo registerStateInfo;
        private readonly common.socks5.Config config;
        private IConnection connection;
        private IClientInfoCaching clientInfoCaching;

        public Socks5ClientHandler(Socks5MessengerSender socks5MessengerSender, RegisterStateInfo registerStateInfo, common.socks5.Config config, IClientInfoCaching clientInfoCaching)
        {
            this.socks5MessengerSender = socks5MessengerSender;
            this.registerStateInfo = registerStateInfo;
            this.config = config;
            this.clientInfoCaching = clientInfoCaching;
        }

        public Socks5EnumAuthType HandleRequest(ulong id, Memory<byte> buffer)
        {
            GetConnection();
            Socks5EnumAuthType socks5EnumAuthType = socks5MessengerSender.Request(new Socks5Info { Id = id, Data = buffer }, connection).Result;
            return socks5EnumAuthType;
        }

        public Socks5EnumAuthState HandleAuth(ulong id, Memory<byte> buffer)
        {
            GetConnection();
            Socks5EnumAuthState socks5EnumAuthState = socks5MessengerSender.Auth(new Socks5Info { Id = id, Data = buffer }, connection).Result;
            return socks5EnumAuthState;
        }

        public Socks5EnumResponseCommand HandleCommand(ulong id, Memory<byte> buffer)
        {
            GetConnection();
            Socks5EnumResponseCommand socks5EnumResponseCommand = socks5MessengerSender.Command(new Socks5Info { Id = id, Data = buffer }, connection).Result;
            return socks5EnumResponseCommand;
        }

        public void HndleForward(ulong id, Memory<byte> buffer)
        {
            GetConnection();
            socks5MessengerSender.Forward(new Socks5Info { Id = id, Data = buffer }, connection).Wait();
        }

        public void Close(ulong id)
        {
            GetConnection();
            _ = socks5MessengerSender.RequestClose(id, connection);
        }
        public void Flush()
        {
            connection = null;
            GetConnection();
        }

        private void GetConnection()
        {
            if (connection == null)
            {
                if (string.IsNullOrWhiteSpace(config.TargetName))
                {
                    connection = SelectConnection(config.TunnelType, registerStateInfo.TcpConnection, registerStateInfo.UdpConnection);
                }
                else
                {
                    var client = clientInfoCaching.GetByName(config.TargetName);
                    connection = SelectConnection(config.TunnelType, client.TcpConnection, client.UdpConnection);
                }
            }
        }
        private IConnection SelectConnection(TunnelTypes tunnelType, IConnection tcpconnection, IConnection udpconnection)
        {
            return tunnelType switch
            {
                TunnelTypes.TCP_FIRST => tcpconnection != null ? tcpconnection : udpconnection,
                TunnelTypes.UDP_FIRST => udpconnection != null ? udpconnection : tcpconnection,
                TunnelTypes.TCP => tcpconnection,
                TunnelTypes.UDP => udpconnection,
                _ => tcpconnection,
            };
        }


    }
}
